﻿module xenObjects;
//import derelict.opengl.extension.arb.vertex_buffer_object;
import derelict.opengl.glext;
//import Xenocide;
import xenocide;
import xenGameState;
import xenActuator;
import Dijkstra;

import tango.util.container.LinkedList;

import tango.util.container.HashMap;

import tango.io.Stdout;

import blaze.all;

import Contour;

struct BehaviourData
{
	LinkedList!(float[]) positions;
	BaseObject target;
	float distance;
	
	bool shift,alt,ctrl;
	
}
class FetchBehaviour:CompositeBehaviour
{
	float[2] initPos;
	this(BaseActor iParent,BehaviourData iData)
	{
		super(iParent,iData);
		desc="Fetch behaviour";
		if (!data.target)
		{
			fail("No target");
			finished=true;
			dispose();
			return;
		}
		initPos[]=parent.position[];
		
		subBehaviourChain.add(new MoveBehaviour(parent,data));
        subBehaviourChain.add(new AttachBehaviour(parent,data));

		data.target=null;
		data.positions.clear();
		data.positions.add(initPos);

        subBehaviourChain.add(new MoveBehaviour(parent,data));
        subBehaviourChain.add(new DetachBehaviour(parent,data));

	
	}
}

class CompositeBehaviour:Behaviour
{
	LinkedList!(Behaviour) subBehaviourChain;
	Behaviour currentBehaviour;
	bool result;
	
	this(BaseActor iParent,BehaviourData iData)
	{
		super(iParent,iData);
		subBehaviourChain=new LinkedList!(Behaviour)();
		result=true;
	}
	
	void loop(float dt)
	{
		if (currentBehaviour)
		{
			if (currentBehaviour.finished)
			{
				result=currentBehaviour.result;
				currentBehaviour.dispose();
				if (!result) fail("");
			}
			else
			{
				currentBehaviour.loop(dt);
				return;
			}
		}
		if (!subBehaviourChain.isEmpty())
		{
			currentBehaviour=subBehaviourChain.removeTail();
			Stdout.formatln("{} is switching to behaviour {}",parent.name,currentBehaviour.desc);
			currentBehaviour.start(result);
		}
		else finished=true;
		
		
	}
	void dispose()
	{
		if (currentBehaviour) currentBehaviour.dispose();
		currentBehaviour=null;
		subBehaviourChain.clear();
	}
}
class Behaviour
{
	uint id;
	char[] desc="IDLE";
	
	BaseActor parent;
	bool result;
	bool finished;
	bool shift,alt,ctrl;
	
	BehaviourData data;
	
	this(BaseActor iParent,BehaviourData iData)
	{
		result=false;
		finished=false;
		parent=iParent;
		
//~ 		if (iData is cast(BehaviourData)null)
//~ 		{
//~ 			fail("NO DATA from "~iParent.name);
//~ 			return;
//~ 			
//~ 		}
		data=iData;
		shift=data.shift;
		ctrl=iData.ctrl;
		alt=iData.alt;
	}
	void fail(char[] text)
	{
		Stdout.formatln(desc~" failed : "~text);
		finished=true;
		result=false;
		
	}
	void start(bool iResult)
	{
		if (!iResult)
		{
			fail("previous action failed");
			
		}
	}
	
	void loop(float dt)
	{
		
	}
	
	void dispose()
	{
		
	}
}
class DetachBehaviour:Behaviour
{
	
	this(BaseActor iParent,BehaviourData iData)
	{
		super(iParent,iData);
		desc="Detach behaviour";
	}
	
	void start(bool result)
	{
		super.start(result);
		finished=true;
		
		if (!result)
		{
			return ;
		}
		auto cp=parent.components[BaseActor.ComponentID.tow];
		if (!cp)
		{
			fail("No tow coponent");
			return;
		}
		this.result=(cast(TractorBeam)cp).detach();
		
	}
}

class AttachBehaviour:Behaviour
{
	BaseActor target;
	
	this(BaseActor iParent,BehaviourData iData)
	{
		super(iParent,iData);
		desc="Attach behaviour";
	}
	
	void start(bool result)
	{
		super.start(result);
		finished=true;
		if (!result)
		{
			return ;
		}
		target=cast(BaseActor)data.target;
		if (target)
		{
			auto cp=parent.components[BaseActor.ComponentID.tow];
			if (!cp)
			{
				fail("No tow coponent");
				return;
			}
			this.result=(cast(TractorBeam)cp).attach(target);
		}
	
	}
	
	
}
class MoveBehaviour:Behaviour
{
	LinkedList!(float[]) waypoints;
	float proximity;
	BaseObject target;
	float[] destination;
	
	this(BaseActor iParent,BehaviourData iData)
	{
		super(iParent,iData);
		desc="Move behaviour";
		waypoints=new LinkedList!(float[])();
		
		proximity=(iData.distance>0)? iData.distance*0.8f:10f;
		
		target=iData.target;
		
		if (target)
		{
			float[] dest;
			dest.length=2;
			
			dest[]=target.position;
			addWayPoint(dest,shift);
		}
		else if (data.positions)
		{
			
			foreach(pt;data.positions)
			{
				addWayPoint(pt,shift);
			}
		}
		parent.bzbody.wakeup();
		
		
	}
	void clearPath()
	{
		waypoints.clear();
		destination=null;
		
	}
	
	void addWayPoint(float[] dest,bool clear)
	{
		if(clear) clearPath();
		waypoints.add(dest);
		
	}
	
	void loop(float dt)
	{
		auto cp=parent.components[BaseActor.ComponentID.engine];
		if (!cp)
		{
			finished=true;
			result=false;
			return;
		}

		if (destination)
		{
			float[] delta;
			delta.length=2;
			delta[0]=parent.position[0]-destination[0];
			delta[1]=parent.position[1]-destination[1];
			//Stdout.formatln("Destination : {}",delta);
			float d=sqrt(delta[0]*delta[0]+delta[1]*delta[1]);
				
			if (d<proximity)
			{
				if (cp)
				{
					auto eng=cast(Engine)cp;
					eng.stop();
					
				}
				destination=null;
				
			}
			
		}
		if (!destination)
		{
			if(!waypoints.isEmpty())
			{
				destination=waypoints.removeTail();
				if (cp)
				{
					auto eng=cast(Engine)cp;
					eng.move(destination);
					
				}
			}
			else
			{
				finished=true;
				result=true;
			}
		}
	}
	
	void dispose()
	{
		auto cp=parent.components[BaseActor.ComponentID.engine];
		auto eng=cast(Engine)cp;
		eng.stop();
		
	}


}	
class Component
{
    
    char[] desc="Generic component";
    BaseActor parent;
    float[2] position;
    float angle;
    int ID;
    bool active;
    
    this(BaseActor iParent,float[2] iPos,float iAngle)
    {
        parent=iParent;
        position[]=iPos;
        angle=iAngle;
        active=true;
        ID=parent.ComponentID.none;
    }   
	void draw(float dt)
	{
	}

	void loop(float dt) {}
    

}
class TractorBeam:Component
{
	BaseActor payload;
	float range, range2,power;
	bzBungee2 bungee;
	
	this(BaseActor iParent,float[2] iPos,float iAngle,float iRange,float iPower)
	{
		super(iParent,iPos,iAngle);
		power=iPower;
		range=iRange;
		range2=range*range;
		active=true;
        payload=null;
		
	}
	bool attach(BaseActor target)
	{
		if (payload) detach();
		if (!target) return false;
		
		
		float dx =parent.position[0]-target.position[0];
		float dy =parent.position[1]-target.position[1];
		float d=(dx*dx+dy*dy);
		if (d>range2)
		{
			Stdout.formatln("Target too far !!! {} vs {}",sqrt(d),range);
			return false;
		}
		payload=target;
		bungee = new bzBungee2 (parent.bzbody,payload.bzbody,5f,sqrt(d),.8f,bzVec2(position[0],position[1]),bzVec2.zeroVect);
        parent.parent.world.addForce(bungee);
		return true;
		
	}
	bool detach()
	{
		payload=null;
		parent.parent.world.removeForce(bungee);
		bungee=null;
		return true;	
	}
	void loop (float dt)
	{
		if (!active) return;
		if (!bungee) return;
		float dx =parent.position[0]-payload.position[0];
		float dy =parent.position[1]-payload.position[1];
		float d=(dx*dx+dy*dy);
		
		if (d>range2*1.25f) detach();
		
		
	}
	
}

class Engine:Component
{
	float power,maxAngle;
	bzThruster thruster;
	bzVec2 direction,destination;
	
	this(BaseActor iParent,float[2] iPos,float iAngle,float iPower,float iMaxAngle)
	{
		super(iParent,iPos,iAngle);
		power=iPower;
		maxAngle=iMaxAngle/180*3.141592f;
		
		bzVec2 pt,force;
		pt.set(iPos[0],iPos[1]);
		direction=bzVec2.forAngle(iAngle-180f);
		force=bzVec2.forAngle(iAngle-180f);
        thruster = new bzThruster(parent.bzbody,pt,force,false);

		parent.parent.world.addForce(thruster);
		active=false;
		
	}
	void move(float[] iTarget)
	{
		if (iTarget.length==2)
		{
			destination.set(iTarget[0],iTarget[1]);
			active=true;
		}	
	}
	void loop(float dt)
	{
		if (active)
		{
			bzVec2 diff;
			diff=destination-parent.bzbody.position;
			float th=-direction.angle(diff)+parent.bzbody.angle;
			//Stdout.formatln("Angle = {} {}",th/3.141592*180,direction.angle(diff)/3.141592*180);
			//Stdout.("target / pos = {}/{} {}",destination.x,destination.y,parent.position);
			float si=(th<0)?-1f:1f;
			float phi=xenWindow.min(abs(th),abs(maxAngle))*si;
			thruster.force.forAngleEquals(phi);
			
			float f=xenWindow.min(power,diff.lengthSquared()*0.01f);
			thruster.force*=f;
			thruster.firing(true);
		}
		else
		{
			thruster.firing(false);
		}
	}
	
	void stop()
	{
		active=false;
		thruster.firing(false);
	}
	
}

class Radar:Component
{
	float range;
	this(BaseActor iParent,float[2] iPos,float iAngle,float iRange)
	{
		
		super(iParent,iPos,iAngle);
		range=iRange;
			}
	void drawTest()
	{
		glPushMatrix();
		glTranslatef(parent.position[0]+30,parent.position[1]+20,0.);
		glScalef(20f,10f,1f);
		glBegin(GL_TRIANGLE_FAN);
			glColor4f (1.,1.0,1.0,1.);
			glVertex2f(0f,0f);
			int th=0;
			while (th<=360)
			{
				
				
				glVertex2f(parent.parent.icos[th%360] ,parent.parent.isin[th%360]);
				th+=10;
			}
		glEnd();

		glPopMatrix();
	}
	void draw (float dt)
	{
		if (!active) return;
		
		//Stdout.formatln("WorldPos {},{}",wp[0],wp[1]);
		
		//drawTest();
		glPushAttrib(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_ENABLE_BIT);
	
        glClearStencil(0);
        glClear(GL_STENCIL_BUFFER_BIT);
		glColorMask(0,0,0,0);
        glDepthMask(0);

        //## enable stencil buffer
        glEnable(GL_STENCIL_TEST);
        //## write a one to the stencil buffer everywhere we are about to draw
        glStencilFunc(GL_ALWAYS, 1, 0xFFFFFFFF);
        //## this is to always pass a one to the stencil buffer where we draw
        glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);


		// dessiner les ombres...
		
		foreach(a;parent.parent.actors)
		{
			if (a!is parent) a.drawShadow(parent.position,range);
		}
		
		foreach(ic;parent.parent.icebergs)
		{
			ic.drawShadow(parent.position,range);
		}
		glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
        //glDepthMask(GL_TRUE);
		
		glStencilFunc(GL_EQUAL, 0, 0xFFFFFFFF);

        //## don't modify the contents of the stencil buffer
        glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
	
		glPushMatrix();
		glTranslatef(parent.position[0],parent.position[1],0.);
        glRotatef(parent.angle,0,0,1);
        glTranslatef(position[0],position[1],0.);
        glRotatef(angle,0.,0.,1.);
        glScalef(range,range,1f);
        glEnable(GL_BLEND);

        glCallList(parent.parent.DL.radarFan);
        
        glDisable(GL_BLEND);
        glPopMatrix();
        glDisable(GL_STENCIL_TEST);
        glPopAttrib();
        
        

	}
	
}
interface Selectable
{
	bool isSelectable();
	bool isSelected();
	void setSelected(bool value);
	void doAction(BehaviourData bd);
	int on_key_press(int key,bool shift,bool ctrl, bool alt);
	int on_key_release(int key,bool shift,bool ctrl, bool alt);
	
}

class BaseObject
{
	char[] name,desc;
	float[2] position;
	public float angle;
	xenGS parent;
	
	
	static enum  Action {none=0,move,attach,detach,fetch};
    
	static enum ActionMode {wait=0,move,attach,detach,fetch};
    
	int[ActionMode.sizeof+1] actionTypeMap;
	void delegate(BehaviourData)[Action.sizeof+1] actionSubMap;
    HashMap!(int,int) actionKeyMap;    
        
	LinkedList!(Behaviour) behaviourQueue;
	int currentAction;
    
	Behaviour currentBehaviour;
	int actionMode,defaultActionMode;
    
    bool isDead;
    
    float extraDamage;
	
    float initialHP,HP;
	
	int ID;
	
	this(xenGS iParent,char[] iName,uint iID,float[2] iPos)
	{
		desc="BaseObject";
        parent=iParent;
		name=iName;
		position[]=iPos;
		ID=iID;
		angle=0f;
		currentAction=Action.none;
		
		behaviourQueue=new LinkedList!(Behaviour)();
		
        
        //actionTypeMap = new HashMap!(int,int)();
		actionKeyMap = new HashMap!(int,int)();
		//actionSubMap=new  HashMap!(int,void function())();
		
		actionMode=defaultActionMode=ActionMode.wait;
		
		actionKeyMap[SDLK_s]=ActionMode.wait;//M
        actionTypeMap[ActionMode.wait]=Action.none;
        actionSubMap[Action.none]=&stopAction;
        
        
        
        isDead=false;
        initialHP=HP=100f;

   
	}

	float[] getWorldPos(float iX,float iY)
	{
		float s,c,X,Y;
		
		float iPh=angle*PI/180;
		s=sin(iPh);
		c=cos(iPh);
		X=position[0]+iX*c+iY*s;
		Y=-iX*s+iY*c+position[1];
		
		return [X,Y];
		
	}
    void stopAction(BehaviourData data)
    {
         setIdle();
    }
    
    float distanceTo(float[2] pos)
	{
		float dx=pos[0]-position[0];
		float dy=pos[1]-position[1];
		return sqrt(dx*dx+dy*dy);
	}
    
    void dispose()
    {
        setIdle();
    }
    
    void draw(float dt){}
    
    void drawComponents(float dt){}
    
    void step(float dt)
    {
        if (currentBehaviour)
        {
            if (!currentBehaviour.finished)
			{
                currentBehaviour.loop(dt);
				//Stdout.formatln("Current behaviour loop !");
            }
			else
			{
                currentBehaviour.dispose();
				currentBehaviour=null;			}
        }
        if (!currentBehaviour)
        {
            if(behaviourQueue.size()>0)
            {
                currentBehaviour=behaviourQueue.removeTail();
                currentBehaviour.start(true);
				Stdout.formatln("Next behaviour !");
            }
        }
        
    }
    
    void setIdle()
    {
        
		behaviourQueue.clear();
		currentAction=Action.none;
		if (currentBehaviour) currentBehaviour.dispose();
        currentBehaviour=null;
        Stdout.formatln("Actor {} stopped",this.name);
    }
    
    void doAction(BehaviourData data)
    {
        auto at=actionTypeMap[actionMode];
        actionSubMap[at](data);
        actionMode=defaultActionMode;
    }
    
    
    void applyDamage(float damage)
    {
        HP-=damage;
        if (HP<=0) isDead=true ;
    }
	int on_key_press(int key,bool shift,bool ctrl, bool alt)
	{
		switch (key)
		{
			case SDLK_s:
				setIdle();
				return 1;
				break;
			default:
			break;
		}
		return 0;
	}
}
class Beacon:BaseObject,Selectable
{
	Sprite[] sprites;
	SineActuator actuator;
	float amplitude;
	long period;
	bool selectable,selected;
	LinkedList!(Beacon) neighbours;
	HashMap!(Beacon,float) neighbour_dist;
	Beacon dijkstraPrevious;
	
	Beacon getPathPrevious() {return dijkstraPrevious;}
	void setPathPrevious(Beacon A) {dijkstraPrevious=A;}
	
	this(xenGS iParent,char[] iName,float[2] iPos)
	{
        auto iID=iParent.getNewID();
		super (iParent,iName,iID,iPos);
        desc="Base Actor";
		amplitude=0.5f;
		period=500;
		actuator=new SineActuator(0,-amplitude,period/2);
		sprites.length=2;
		sprites[0].load(parent.getNewID(),"res/red_light.png",8,8);
		sprites[1].load(parent.getNewID(),"res/violet_light.png",8,8);
		neighbours=new LinkedList!(Beacon)();
		neighbour_dist=new HashMap!(Beacon,float)();
		
		selected=false;
		selectable=true;
		
		
		actionSubMap[Action.none]=&doLink;
        
	}
	void draw(float dt)
	{
		
		int np=neighbours.size();
		if (np>0)
		{
			glPushAttrib(GL_LINE_STIPPLE|GL_BLEND|GL_COLOR_BUFFER_BIT);
            glEnable(GL_LINE_STIPPLE);
            glLineWidth(1);
            //glEnable(GL_BLEND);
            //glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
        
            //glLineStipple(3,0xAFAF);
			glBegin(GL_LINES);
			glColor4f(0.8,0.0,0.5,0.5);
				
            foreach(b;neighbours)
			{
				glVertex2f(position[0] ,position[1]);
				glVertex2f(b.position[0] , b.position[1]);
			}
			glEnd();
            glPopAttrib();
        
			
		}
		
		auto res=actuator.val();
        if (res.finished)
            actuator.restart(res.value,-res.value,period);
        int i= (selected)?0:1; 
        sprites[i].scale=1.+res.value;
		
		glPushMatrix();
        glTranslatef(position[0],position[1],0.);
        
       
        sprites[i].draw();
        
        glPopMatrix();
	}
	void setSelected(bool value)
    {
        selected=value;
    }
	bool isSelectable(){return selectable;}
	bool isSelected(){return selected;}
	
	void doLink(BehaviourData data)
    {
        
		auto target=cast(Beacon)data.target;
		if (target)
		{
			Stdout.formatln("It is a beacon");
			if (target !is this)
			{
				if (neighbours.contains(target))
				{
					Stdout.formatln("DETACH {}",target.name);
					detach(target);
				}else
				{
					Stdout.formatln("ATTACH {}",target.name);
					attach(target,-1f);
				}
			} else Stdout.formatln("It is me, you fool !");
		}else
		{
			if (data.positions)
			{
				float[2] pos;
				foreach(p;data.positions)
				{
					pos[]=p;
					auto b=parent.spawnBeacon(pos);
					attach(b,-1f);
					parent.selectActor(b,true);
				}
			}
		}
		
    }

	void attach(Beacon B, float dist)
	{
		if (!B) return;
		
		if (!neighbours.contains(B))
		{
			if (dist<0) dist=distanceTo(B.position);
			
			neighbours.add(B);
			neighbour_dist[B]=dist;
			B.attach(this,dist);
			
		}
		
	}
	void detach(Beacon B)
	{
		if (neighbours.contains(B))
		{
			neighbour_dist.removeKey(B);
			neighbours.remove(B);
			B.detach(this);
		}
		
	}

	int on_key_release(int key,bool shift,bool ctrl, bool alt)
	{
		return 0;
	}
	
	int on_key_press(int key,bool shift,bool ctrl, bool alt)
	{
		return 0;
	}
	
	void doAction(BehaviourData data)
    {
        
		super.doAction(data);
		
    }
}
class BaseActor:BaseObject,Selectable
{
    bzBody bzbody;
//    float [] silhouette_rel,silhouette;
//	uint [] shadow_indices;
    
	float radius;
	float angle,angle_rad;
    
    float[2] destination;
    BaseObject target;
    
    float maxSpeed,maxAcc;
    
    static enum ComponentID {none,tow,radar,engine,bomb};
    
	Component [ComponentID.sizeof] components;
	
	bool selectable,selected;
	
	Contour silhouette;
    
    
    this(xenGS iParent,char[] iName,uint iID,float[2] iPos,float [][] iContour)
	{
        super (iParent,iName,iID,iPos);
        desc="Base Actor";
        
        maxSpeed=100f;
        maxAcc=80f;
		angle_rad=angle=0f;
    
		silhouette=new Contour(iID,iContour,true,[0f,0f],[1f,0.5f,0f]);
        
		initBody();
        
		actionKeyMap[SDLK_m]=ActionMode.move;//M
        actionTypeMap[ActionMode.move]=Action.move;
        actionSubMap[Action.move]=&moveAction;
        
		actionKeyMap[SDLK_s]=ActionMode.move;//M
        actionTypeMap[ActionMode.move]=Action.move;
        actionSubMap[Action.move]=&moveAction;
        
		actionKeyMap[SDLK_a]=ActionMode.attach;//A
        actionTypeMap[ActionMode.attach]=Action.attach;
        actionSubMap[Action.attach]=&attachAction;

		actionKeyMap[SDLK_d]=ActionMode.detach;//D
        actionTypeMap[ActionMode.detach]=Action.detach;
        actionSubMap[Action.detach]=&detachAction;
       
        actionKeyMap[SDLK_f]=ActionMode.fetch;//F
        actionTypeMap[ActionMode.fetch]=Action.fetch;
        actionSubMap[Action.fetch]=&fetchAction;
       
		components[ComponentID.engine]=new Engine(this,[-0.9,0],180f,2f,60f);
		components[ComponentID.tow]=new TractorBeam(this,[-0.3,0],180f,20f,0.1f);
		
		selected=false;
 
		selectable=true;
		actionMode=defaultActionMode=ActionMode.move;
    }
	

	void initBody()
	{
		
		bzVec2[] bzLoop;
		
		uint n=bzLoop.length=silhouette.nVert;
		uint j=0,i;
		for (i=0;i<n;i++)
		{
			
			bzLoop[i].set(silhouette.silhouette[j++],silhouette.silhouette[j++]);
			
		}		
		
		bzBodyDef bd = new bzBodyDef();
		bd.position.set( position[0],position[1] );
		bd.linearDamping = 0.08f;
		bd.angularDamping = 0.14f;
		
		bzbody = parent.world.createBody(bd);
		
		bzPolyDef sd = new bzPolyDef();
		//sd.setAsBox(1f, 1f);
        
		//Stdout.formatln("hello");
		sd.vertices.length = bzLoop.length;
		sd.vertices[] = bzLoop[];
		sd.density=1f;
		//bzBody.setMassFromShapes();
		bzbody.createShape(sd);
		bzbody.setMassFromShapes();
		/*bzMassData md;
		md.mass=3f;
		md.center.zero();
		md.I=40f;
		bzbody.setMass(md);
		*/
		
		
		
	}
    
    void moveAction(BehaviourData data)
    {
        if (data.shift) setIdle();
		if (data.ctrl) {
			Stdout.formatln("Dijkstra requested");
			float[2] dest=data.positions.head();
			auto path=parent.getDijkstraPath(position,dest);
			
			if (path !is null)
			{
				foreach(p;path)
					Stdout.formatln("... positions : {}/{} " ,p[0],p[1]);
				data.positions=path;
			}
				
		}		
		behaviourQueue.add(new MoveBehaviour(this,data));

    }
	void attachAction(BehaviourData data)
    {
        behaviourQueue.add(new AttachBehaviour(this,data));
		Stdout.formatln("Next Behavioue : attach {}",data.positions.head());
    }
	void detachAction(BehaviourData data)
    {
        behaviourQueue.add(new DetachBehaviour(this,data));
		Stdout.formatln("Next Behaviour : detach {}",data.positions.head());
    }
	void fetchAction(BehaviourData data)
    {
        behaviourQueue.add(new FetchBehaviour(this,data));
		Stdout.formatln("Next Behaviour : fetch {}",data.positions.head());
    }
	
	void drawComponents(float dt)
	{
		foreach(cmp;components)
		{
			if (cmp)
			{ 
				cmp.draw(dt);
				
			}
		}
		
	}
	
	
	void draw(float dt)
	{
		glPushMatrix();
		glTranslatef(position[0],position[1],0f);
		glRotatef(angle,0f,0f,1f);
		silhouette.draw();
		glPopMatrix();
	}
	void drawShadow(float [2] origin,float range)
	{
		if (silhouette.updateShadow(origin,range)) silhouette.drawShadow(); 
	}

    void step(float dt)
	{
		//Stdout.formatln(" angle = {}",angle);
		position[0]=bzbody.position.x;
		position[1]=bzbody.position.y;
		angle=bzbody.angle*180f/3.141592;
		angle_rad=bzbody.angle;
		silhouette.updatePositionAndAngle(position,angle_rad);
		foreach (c;components)
		{
			if (c) c.loop(dt);
		}
		super.step(dt);
		
		
	}
	
	int on_key_release(int key,bool shift,bool ctrl, bool alt)
	{
		return 0;
	}
	
	int on_key_press(int key,bool shift,bool ctrl, bool alt)
	{
		if (super.on_key_press(key,shift,ctrl,alt)!=0) return 1;
		
		int am;
		
		if (actionKeyMap.get(key,am))
			{
				actionMode=am;
				Stdout.formatln(" Action set to {}",actionMode);
				return 1;
			}
		return 0;
		
		
	}
	void setSelected(bool value)
    {
        if (value)
            actionMode=defaultActionMode;
        selected=value;
    }
	bool isSelectable(){return selectable;}
	bool isSelected(){return selected;}
	
	void doAction(BehaviourData data)
    {
        
		super.doAction(data);
		
    }



}

class Iceberg:BaseObject
{
	
    float radius;

	Contour silhouette;
    
	this(xenGS iParent,char[] iName,uint iID,float[][]iPts,bool invert,float iFactor)
	{
		float pos[2];
		int n;
		n=iPts.length;
		pos[0]=pos[1]=0f;
		foreach(p;iPts)
		{
			pos[0]+=p[0];
			pos[1]+=p[1];
			
        }
		pos[0]/=n;
		pos[1]/=n;
		
		super(iParent,iName,iID,pos);
		//float[] colors=[0f,0.5f,8f];
		silhouette=new Contour(iID,iPts,invert,pos,[0f,0.5f,0.8f]);
		
		
	}
	
	
	void draw(float dt)
	{
		silhouette.draw();
		
	}
	void drawShadow(float [2] origin,float range)
	{
		if (silhouette.updateShadow(origin,range)) silhouette.drawShadow(); 
	}
}
